package cc.z8g.browser;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.MenuItem;
import android.view.View;
import android.webkit.WebView;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.RadioButton;

import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import cc.z8g.browser.core.BrowserConst;
import cc.z8g.browser.database.Bookmark;
import cc.z8g.browser.database.bookmark.BookmarkDAO;
import cc.z8g.browser.database.bookmark.BookmarkParser;
import cc.z8g.browser.dialog.BrowserDialog;
import cc.z8g.browser.dialog.DialogItem;
import cc.z8g.browser.utils.MiscUtils;
import cc.z8g.browser.utils.sp.UserSp;
import cc.z8g.browser.search.suggestions.SearchConst;
import cc.z8g.browser.utils.ThreadPool;
import cc.z8g.browser.utils.WebUtils;
import io.reactivex.rxjava3.core.Single;

/**
 * SimpleSettingsActivity
 *
 * @author zhaoxuyang.net
 * @since 2024-08-07
 */
public class SimpleSettingsActivity extends ThemableSettingsActivity {
    static final int IMPORT_FILE_REQUEST_CODE = 100;
    static final int EXPORT_FILE_REQUEST_CODE = 101;
    static final String TEXT_MIME_TYPE = "text/*";

    static final String EXTENSION_HTML = "html";
    static final String BOOKMARK_EXPORT_FILE = "ExportedBookmarks.txt";


    @Override
    protected void onCreate(@Nullable final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.simple_settings_root);

        // 显示返回按钮
        setSupportActionBar(findViewById(R.id.toolbar));
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setTitle(R.string.settings);
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

        initButton(this); // 绑定一些按钮的点击事件

        if (BuildConfig.DEBUG) {
            initCheckBox(R.id.settings_leak_canary, UserSp.KEY_LEAK_CANARY);
            findViewById(R.id.settings_debug_layout).setVisibility(View.VISIBLE);
        }

        initCheckBox(R.id.settings_enable_javascript, UserSp.KEY_JAVASCRIPT);
        initCheckBox(R.id.settings_allow_open_new_window, UserSp.KEY_POPUPS);
        initCookieCheckBox(this);
        initCheckBox(R.id.settings_do_not_track, UserSp.KEY_DO_NOT_TRACK);
        initCheckBox(R.id.settings_enable_location, UserSp.KEY_LOCATION);
        initCheckBox(R.id.settings_remove_identifying_headers, UserSp.KEY_REMOVE_IDENTIFYING_HEADERS);
        initCheckBox(R.id.settings_webrtc_support, UserSp.KEY_WEB_RTC);
        initCheckBox(R.id.settings_exit_clear_cache, UserSp.KEY_EXIT_CLEAR_CACHE);
        initCheckBox(R.id.settings_exit_clear_history, UserSp.KEY_EXIT_CLEAR_HISTORY);
        initCheckBox(R.id.settings_exit_clear_cookies, UserSp.KEY_EXIT_CLEAR_COOKIES);
        initCheckBox(R.id.settings_exit_clear_web_storage, UserSp.KEY_EXIT_CLEAR_WEB_STORAGE);

        // 性能与节能
        initCheckBox(R.id.settings_add_save_data, UserSp.KEY_SAVE_DATA);
        initCheckBox(R.id.settings_cb_images, UserSp.KEY_BLOCK_IMAGES);

        // 外观
        initCheckBox(R.id.settings_use_website_theme_color, UserSp.KEY_THEME_COLOR);
        initCheckBox(R.id.settings_full_screen, UserSp.KEY_FULL_SCREEN);
        initCheckBox(R.id.settings_black_status_bar, UserSp.KEY_BLACK_STATUS_BAR);
        initCheckBox(R.id.settings_wide_view_port, UserSp.KEY_USE_WIDE_VIEWPORT);
        initCheckBox(R.id.settings_over_view_mode, UserSp.KEY_OVERVIEW_MODE);
        initCheckBox(R.id.settings_reflow, UserSp.KEY_TEXT_REFLOW);

        // 地址栏内容
        initRadioButtonInt(this, R.id.settings_box_display_domain, UserSp.KEY_BOX_DISPLAY, UserSp.BOX_DISPLAY_DOMAIN, null);
        initRadioButtonInt(this, R.id.settings_box_display_url, UserSp.KEY_BOX_DISPLAY, UserSp.BOX_DISPLAY_URL, null);
        initRadioButtonInt(this, R.id.settings_box_display_title, UserSp.KEY_BOX_DISPLAY, UserSp.BOX_DISPLAY_TITLE, null);

        // 主题样式
        initRadioButtonInt(this, R.id.settings_theme_light, UserSp.KEY_THEME, UserSp.THEME_LIGHT, null);
        initRadioButtonInt(this, R.id.settings_theme_dark, UserSp.KEY_THEME, UserSp.THEME_DARK, null);
        initRadioButtonInt(this, R.id.settings_theme_black, UserSp.KEY_THEME, UserSp.THEME_BLACK, null);

        // 文本缩放比例
        initRadioButtonInt(this, R.id.settings_text_size_50, UserSp.KEY_TEXT_ZOOM, -50, null);
        initRadioButtonInt(this, R.id.settings_text_size_75, UserSp.KEY_TEXT_ZOOM, -25, null);
        initRadioButtonInt(this, R.id.settings_text_size_100, UserSp.KEY_TEXT_ZOOM, 0, null);
        initRadioButtonInt(this, R.id.settings_text_size_125, UserSp.KEY_TEXT_ZOOM, 25, null);
        initRadioButtonInt(this, R.id.settings_text_size_150, UserSp.KEY_TEXT_ZOOM, 50, null);
        initRadioButtonInt(this, R.id.settings_text_size_200, UserSp.KEY_TEXT_ZOOM, 100, null);

        // 搜索引擎
        EditText engineUrlEditText = bindEditTextDoneAction(this, R.id.search_engine_url_edit_text, UserSp.KEY_SEARCH_ENGINE_CUSTOM_URL);
        initRadioButtonInt(this, R.id.search_engine_google, UserSp.KEY_SEARCH_ENGINE, SearchConst.ENGINE_GOOGLE, null);
        initRadioButtonInt(this, R.id.search_engine_baidu, UserSp.KEY_SEARCH_ENGINE, SearchConst.ENGINE_BAIDU, null);
        initRadioButtonInt(this, R.id.search_engine_bing, UserSp.KEY_SEARCH_ENGINE, SearchConst.ENGINE_BING, null);
        initRadioButtonInt(this, R.id.search_engine_custom, UserSp.KEY_SEARCH_ENGINE, SearchConst.ENGINE_CUSTOM, engineUrlEditText);

        // 搜索建议
        initRadioButtonInt(this, R.id.search_suggestion_baidu, UserSp.KEY_SEARCH_SUGGESTION, SearchConst.SUGGESTION_BAIDU, null);
        initRadioButtonInt(this, R.id.search_suggestion_google, UserSp.KEY_SEARCH_SUGGESTION, SearchConst.SUGGESTION_GOOGLE, null);
        initRadioButtonInt(this, R.id.search_suggestion_off, UserSp.KEY_SEARCH_SUGGESTION, SearchConst.SUGGESTION_NONE, null);

        // 启动页
        EditText startPageUrlEditText = bindEditTextDoneAction(this, R.id.start_page_url_text_view, UserSp.START_PAGE_URL);
        initRadioButtonInt(this, R.id.homepage_web_url, UserSp.KEY_START_PAGE, UserSp.START_PAGE_USE_URL, startPageUrlEditText);
        initRadioButtonInt(this, R.id.action_bookmarks, UserSp.KEY_START_PAGE, UserSp.START_PAGE_USE_BOOKMARKS, null);

        EditText downloadDirEditText = bindEditTextDoneAction(this, R.id.download_dir_edit_view, UserSp.KEY_DOWNLOAD_DIR);
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // android 10 之后不能直接往 sdcard 写
            downloadDirEditText.setEnabled(false);
        }
    }

    /** 需要支持 android 9 以上的完全匿名模式 */
    private static void initCookieCheckBox(@NonNull Activity activity) {
        CheckBox cb1 = activity.findViewById(R.id.settings_enable_third_party_cookie);
        boolean cookieEnable = UserSp.getBoolean(UserSp.KEY_THIRD_PARTY_COOKIES);
        cb1.setChecked(cookieEnable);
        CheckBox cb2 = activity.findViewById(R.id.settings_enable_third_party_cookie_incognito);
        if (MiscUtils.FULL_INCOGNITO) { // 完全匿名模式下，随Cookie走
            cb2.setChecked(cookieEnable);
            cb2.setEnabled(false);
        } else {
            cb2.setChecked(UserSp.getBoolean(UserSp.KEY_INCOGNITO_THIRD_PARTY_COOKIES));
        }

        cb1.setOnCheckedChangeListener((buttonView, isChecked) -> {
            UserSp.putBoolean(UserSp.KEY_THIRD_PARTY_COOKIES, isChecked);
            if (MiscUtils.FULL_INCOGNITO) { // 完全匿名模式下，随Cookie走
                cb2.setChecked(isChecked);
            }
        });
        cb2.setOnCheckedChangeListener((buttonView, isChecked) ->
                UserSp.putBoolean(UserSp.KEY_INCOGNITO_THIRD_PARTY_COOKIES, isChecked)
        );
    }

    private static void initRadioButtonInt(@NonNull Activity activity, @IdRes int id, @NonNull String spKey, int value, @Nullable EditText editText) {
        RadioButton radioButton = activity.findViewById(id);
        radioButton.setOnCheckedChangeListener((buttonView, isChecked) -> {
            if (isChecked) {
                UserSp.putInt(spKey, value);
            }
            if (editText != null) {
                editText.setEnabled(isChecked);
            }
        });
        boolean enable = UserSp.getInt(spKey) == value;
        if (enable) {
            radioButton.setChecked(true);
        }
        if (editText != null) {
            editText.setEnabled(enable);
        }
    }

    private static EditText bindEditTextDoneAction(@NonNull Activity activity, @IdRes int id, @NonNull String spKey) {
        EditText editText = activity.findViewById(id);
        editText.setText(UserSp.getString(spKey));
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
            }

            @Override
            public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
            }

            @Override
            public void afterTextChanged(final Editable s) {
                String text = s.toString();
                UserSp.putString(spKey, text);
            }
        });
        return editText;
    }

    private CheckBox initCheckBox(@IdRes int id, @NonNull String spKey) {
        CheckBox checkBox = findViewById(id);
        if (UserSp.getBoolean(spKey)) {
            checkBox.setChecked(true);
        }
        checkBox.setOnCheckedChangeListener((buttonView, isChecked) ->
                UserSp.putBoolean(spKey, isChecked)
        );
        return checkBox;
    }

    private static void initButton(@NonNull final Activity activity) {
        activity.findViewById(R.id.action_clear_cache).setOnClickListener(v -> {
            WebView webView = new WebView(activity);
            webView.clearCache(true);
            webView.destroy();
            MiscUtils.showToast(activity, R.string.message_cache_cleared);
        });
        activity.findViewById(R.id.action_clear_history).setOnClickListener(v -> {
            BrowserDialog.showPositiveNegativeDialog(activity, R.string.title_clear_history, R.string.dialog_history, null,
                    new DialogItem(null, R.string.action_yes, true, () -> {
                        WebUtils.clearHistory(activity, ThreadPool.getDBScheduler());
                        MiscUtils.showToast(activity, R.string.message_clear_history);
                    }),
                    new DialogItem(null, R.string.action_no, true, null),
                    null);
        });
        activity.findViewById(R.id.action_clear_cookies).setOnClickListener(v -> {
            WebUtils.clearCookies();
            MiscUtils.showToast(activity, R.string.message_cookies_cleared);
        });
        activity.findViewById(R.id.action_clear_web_storage).setOnClickListener(v -> {
            WebUtils.clearWebStorage();
            MiscUtils.showToast(activity, R.string.message_web_storage_cleared);
        });

        // 书签管理
        activity.findViewById(R.id.action_import_bookmarks).setOnClickListener(v -> {
            Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            intent.setType(TEXT_MIME_TYPE);
            activity.startActivityForResult(intent, IMPORT_FILE_REQUEST_CODE);
        });
        activity.findViewById(R.id.action_export_bookmarks).setOnClickListener(v -> {
            Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            intent.setType("text/plain");
            intent.putExtra(Intent.EXTRA_TITLE, BOOKMARK_EXPORT_FILE);
            activity.startActivityForResult(intent, EXPORT_FILE_REQUEST_CODE);
        });
        activity.findViewById(R.id.action_delete_all_bookmarks).setOnClickListener(v -> {
            BrowserDialog.showPositiveNegativeDialog(activity, R.string.action_delete, R.string.action_delete_all_bookmarks, null,
                    new DialogItem(null, R.string.yes, true, () -> BookmarkDAO.Companion.getImpl().deleteAllBookmarks().subscribeOn(ThreadPool.getDBScheduler()).subscribe()),
                    new DialogItem(null, R.string.no, true, null),
                    null);
        });

        // 恢复设置
        activity.findViewById(R.id.action_reset_to_default).setOnClickListener(v -> {
            BrowserDialog.showPositiveNegativeDialog(activity, R.string.dialog_title_settings_reset, R.string.dialog_msg_settings_reset, null,
                    new DialogItem(null, R.string.yes, true, () -> {
                        UserSp.INSTANCE.clearUserSp();
                        activity.finish();
                    }),
                    new DialogItem(null, R.string.no, true, null),
                    null);
        });

        activity.findViewById(R.id.settings_text_encoding).setOnClickListener(v -> {
            AlertDialog.Builder builder = new AlertDialog.Builder(activity);
            builder.setTitle(R.string.settings_text_encoding);
            String spKey = UserSp.TEXT_ENCODING;
            String currEncoding = UserSp.getString(spKey);
            String[] arr = BrowserConst.TEXT_ENCODINGS;
            int index = indexOf(arr, currEncoding); // -1 则不选择
            builder.setSingleChoiceItems(arr, index, (dialog, which) -> {
                UserSp.putString(spKey, arr[which]);
            });
            builder.setPositiveButton(R.string.action_ok, null);
            AlertDialog dialog = builder.create();
            BrowserDialog.setDialogSize(dialog.getContext(), dialog);
            dialog.show();
        });
    }

    private static int indexOf(String[] arr, String str) {
        for (int i = 0; i < arr.length; i++) {
            if (TextUtils.equals(arr[i], str)) {
                return i;
            }
        }
        return -1;
    }

    /** ActionBar 中显示的返回按钮的点击事件 */
    @Override
    public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
        finish();
        return true;
    }

    /** 用于书签管理等 */
    @Override
    protected void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
        if (requestCode == IMPORT_FILE_REQUEST_CODE || requestCode == EXPORT_FILE_REQUEST_CODE) {
            if (resultCode == RESULT_OK && requestCode == IMPORT_FILE_REQUEST_CODE) {
                Uri uri = data == null ? null : data.getData();
                if (uri != null) {
                    importBookmarksFromUri(this, uri);
                }
            } else if (resultCode == RESULT_OK && requestCode == EXPORT_FILE_REQUEST_CODE) {
                Uri uri = data == null ? null : data.getData();
                if (uri != null) {
                    exportBookmarksToUri(this, uri);
                }
            } else {
                MiscUtils.showToast(this, R.string.action_message_canceled);
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }


    @SuppressLint("CheckResult")
    private static void importBookmarksFromUri(Activity activity, Uri uri) {
        ContentResolver cr = activity.getContentResolver();
        try (InputStream fis = cr.openInputStream(uri)) {
            String fileName = MiscUtils.getFileName(cr, uri);
            List<Bookmark.Entry> bookmarkList;
            if (fileName == null || fis == null) {
                MiscUtils.showToast(BrowserApp.getApplication(), R.string.import_bookmark_error);
                return;
            } else if (fileName.endsWith(EXTENSION_HTML)) {
                bookmarkList = BookmarkParser.importBookmarksFromFileStream(fis, BookmarkParser.BOOKMARK_TYPE_NETSCAPE);
            } else {
                bookmarkList = BookmarkParser.importBookmarksFromFileStream(fis, BookmarkParser.BOOKMARK_TYPE_LEGACY);
            }
            BookmarkDAO.Companion.getImpl().addBookmarkList(bookmarkList)
                    .andThen(Single.just(bookmarkList.size()))
                    .subscribeOn(ThreadPool.getDBScheduler())
                    .observeOn(ThreadPool.getMainScheduler())
                    .subscribe(count -> {
                        MiscUtils.showToast(activity, count + " " + activity.getString(R.string.message_import));
                    }, throwable -> {
                        MiscUtils.showToast(BrowserApp.getApplication(), R.string.import_bookmark_error);
                    });
        } catch (Exception e) {
            MiscUtils.showToast(BrowserApp.getApplication(), R.string.import_bookmark_error);
        }
    }

    private static void exportBookmarksToUri(@NonNull Activity activity, @NonNull Uri uri) {
        BookmarkDAO.Companion.getImpl().getAllBookmarksSorted()
                .subscribeOn(ThreadPool.getDBScheduler())
                .subscribe(bookmarkList -> {
                    ContentResolver cr = activity.getContentResolver();
                    String fileName = MiscUtils.getFileName(cr, uri);
                    try (OutputStream fos = cr.openOutputStream(uri)) {
                        if (fos == null) {
                            return;
                        }
                        BookmarkParser.exportBookmarksToOutputStream(bookmarkList, fos)
                                .subscribeOn(ThreadPool.getDBScheduler())
                                .observeOn(ThreadPool.getMainScheduler())
                                .subscribe(() -> MiscUtils.showToast(activity, activity.getString(R.string.bookmark_export_path) + " " + fileName),
                                        throwable -> MiscUtils.showToast(activity, R.string.bookmark_export_failure));

                    } catch (Exception ex) {
                        MiscUtils.showToast(activity, R.string.bookmark_export_failure);
                    }
                });
    }
}
